package com.ruoyi.business.app.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.aliyun.dysmsapi20170525.models.SendSmsResponseBody;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.business.app.bo.*;
import com.ruoyi.business.app.mapper.UserMapper;
import com.ruoyi.business.app.service.IAppUserService;
import com.ruoyi.business.app.utils.JwtUtils;
import com.ruoyi.business.app.vo.AppThirdLoginVo;
import com.ruoyi.business.app.vo.AppUserVo;
import com.ruoyi.business.app.vo.DownloadVo;
import com.ruoyi.business.app.vo.UserAutonymVo;
import com.ruoyi.business.domain.*;
import com.ruoyi.business.enums.AppUserLoginTypeEnum;
import com.ruoyi.business.mapper.*;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.utils.AssertUtils;
import com.ruoyi.common.utils.NameUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.sms.bean.Sms;
import com.ruoyi.common.utils.sms.impl.AliSmsImpl;
import lombok.AllArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
@AllArgsConstructor
public class AppUserServiceImpl extends ServicePlusImpl<UserMapper, HcxAppUser> implements IAppUserService {

    private final StringRedisTemplate stringRedisTemplate;
    private final AliSmsImpl smsSender;

    private final JwtUtils jwtUtils;
    private final HcxUserOpinionsMapper userOpinionsMapper;

    private final HcxUserCouponMapper userCouponMapper;
    private final HcxUserOpinionsPicsMapper opinionsPicsMapper;
    private final RedisCache redisCache;

    private final HcxAppVersionMapper hcxAppVersionMapper;

    private final HcxAppUserMapper hcxAppUserMapper;


    @Override
    @Transactional
    public List<DownloadVo> userRegister(HcxAppUserBo bo) {
        //校验该手机号是否已注册
        HcxAppUser hcxAppUser = getBaseMapper().selectOne(new LambdaQueryWrapper<HcxAppUser>().eq(HcxAppUser::getPhonenumber, bo.getPhonenumber()));
        AssertUtils.isTrue(ObjectUtil.isEmpty(hcxAppUser), "账号已存在，不可以重复注册！");
        //校验验证码
        // AssertUtils.isTrue(authCode(bo.getPhonenumber(), bo.getAuthCode()), "注册失败 ,验证码错误");

        HcxAppUser user = new HcxAppUser();
        user.setPhonenumber(bo.getPhonenumber());
        user.setPassword(SecurityUtils.encryptPassword(bo.getPassword()));
        user.setUserName(bo.getPhonenumber());
        // 昵称
        user.setSex(bo.getSex());
        if (ObjectUtil.isEmpty(bo.getNickName())) {
            user.setNickName(NameUtils.getName());
        } else {
            user.setNickName(bo.getNickName());
        }
        user.setAvatar(bo.getAvatar());
        user.setVipFlag(Constants.ZERO);
        user.setMerchantFlag(Constants.ZERO);
        user.setBalancePrice(new BigDecimal(Constants.ZERO));
        user.setFramPrice(new BigDecimal(Constants.ZERO));
        user.setSharePrice(new BigDecimal(Constants.ZERO));
        user.setMerchantPrice(new BigDecimal(Constants.ZERO));
        // 生成自己的邀请码
        while (true) {
            String yqcode = RandomUtil.randomNumbers(6);
            List<HcxAppUser> listUsers = getBaseMapper().selectList(new LambdaQueryWrapper<HcxAppUser>().eq(HcxAppUser::getInviteCode, yqcode));
            if (CollectionUtil.isEmpty(listUsers)) {
                user.setInviteCode(yqcode);
                break;
            }
        }

        // 父级码
        String inviteFullCode;
        // 前端是否传递邀请码
        String inviteCode = bo.getInviteCode();
        if (ObjectUtil.isNotEmpty(inviteCode)) {
            // 查询邀请人
            HcxAppUser yaoqingUser = getBaseMapper().selectOne(new LambdaQueryWrapper<HcxAppUser>().eq(HcxAppUser::getInviteCode, inviteCode));
            AssertUtils.isTrue(ObjectUtil.isNotEmpty(yaoqingUser), "邀请码不合法");
            inviteFullCode = yaoqingUser.getInviteFullCode() + yaoqingUser.getInviteCode();
        } else {
            // 平台的邀请码为0
            inviteFullCode = Constants.ZERO;
        }
        user.setInviteFullCode(inviteFullCode);
        user.setTwoNum(Long.valueOf(0));


        getBaseMapper().insert(user);


        //返回android下载地址
        List<DownloadVo> list = new ArrayList<>();
        HcxAppVersion hcxAppVersion = hcxAppVersionMapper.selectList(new LambdaQueryWrapper<HcxAppVersion>().orderByDesc(HcxAppVersion::getCreateTime)).get(0);

        DownloadVo vo = new DownloadVo();
        vo.setAppType(hcxAppVersion.getAppType());
        vo.setAppVersion(hcxAppVersion.getAppVersion());
        vo.setFileUrl(hcxAppVersion.getFileUrl());
        list.add(vo);

        return list;
    }

    @Override
    public AjaxResult sendCode(String phonenumber, HttpServletRequest request) throws Exception {
        AssertUtils.isTrue(PhoneUtil.isMobile(phonenumber), Constants.ERROR_PHONE_NUM_TIP);
      /*  // 获取Ip
        String ip = ServletUtils.getClientIP(request);
        //ip存入缓存中
        stringRedisTemplate.opsForValue().increment(Constants.SMS_IP_ADDRESS_KEY + ip);
        stringRedisTemplate.expire(Constants.SMS_TIMES_KEY + ip, Constants.EXPIRE_HOUR, TimeUnit.HOURS);
        // 同一IP地址获取验证码次数
        String ipNum = stringRedisTemplate.opsForValue().get(Constants.SMS_IP_ADDRESS_KEY + ip);
        // 验证码限制次数
        String authIpCodeNumStr = redisCache.getCacheObject(Constants.SYS_CONFIG_KEY + Constants.AUTH_IP_CODE_NUM);

        if (StringUtil.isNotEmpty(ipNum)) {
            if (Integer.parseInt(ipNum) > Integer.valueOf(authIpCodeNumStr)) {
                throw new CustomException("今天获取验证码次数过多");
            }
        }*/
        // todo  调用阿里云sdk发送短信  现在用的我的号 500条短信
        //随机生成的6位验证码
        String code = RandomUtil.randomString("123456789", 6);

        Sms sms = new Sms();
        sms.setTel(phonenumber);
        sms.setCode(code);
        SendSmsResponseBody send = smsSender.send(sms);
        String message = send.getMessage();
        String resultCode = send.getCode();
        if ("OK".equals(resultCode)) {
            stringRedisTemplate.opsForValue().set(phonenumber, code);
            return AjaxResult.success(message);
        } else {
            return AjaxResult.error(message);
        }
    }

    //校验验证码
    @Override
    public boolean authCode(String phonenumber, String authCode) {
        String msgCode = stringRedisTemplate.opsForValue().get(phonenumber);
        return StrUtil.isNotEmpty(msgCode) && msgCode.equals(authCode);
    }

    @Override
    public String pwdLogin(String phonenumber, String password) {
        AssertUtils.isTrue(PhoneUtil.isMobile(phonenumber), "不是合法手机号，请检查");
        HcxAppUser user = getBaseMapper().selectOne(new LambdaQueryWrapper<HcxAppUser>().eq(HcxAppUser::getPhonenumber, phonenumber));
        if (ObjectUtil.isEmpty(user)) {
            throw new CustomException("账号不存在,请先注册!");
        }
        if (ObjectUtil.isNotEmpty(user) && Constants.FOUR.equals(user.getStatus())) {
            throw new CustomException("账号已被冻结，请联系管理员!");
        }
        boolean b = SecurityUtils.matchesPassword(password, user.getPassword());
        AssertUtils.isTrue(b, "账号或密码错误，请检查!");
        String token = jwtUtils.generateToken(user.getId());

        return token;
    }

    @Override
    public String authcodeLogin(String phonenumber, String authCode) {
        AssertUtils.isTrue(PhoneUtil.isMobile(phonenumber), Constants.ERROR_PHONE_NUM_TIP);
        //获取redis中存放的验证码数据
        String phoneCode = stringRedisTemplate.opsForValue().get(phonenumber);
        AssertUtils.isTrue(StrUtil.isNotEmpty(phoneCode), Constants.AUTH_CODE_EXPIRE_TIP);
        //判断验证码是否正确
        AssertUtils.isTrue(authCode.equals(phoneCode), Constants.AUTH_CODE_ERROR_TIP);
        HcxAppUser user = getBaseMapper().selectOne(new LambdaQueryWrapper<HcxAppUser>().eq(HcxAppUser::getPhonenumber, phonenumber));
        if (ObjectUtil.isEmpty(user)) {
            throw new CustomException("手机号不存在,请先注册!");
        }
        if (user != null && user.getStatus().equals(Constants.FOUR)) {
            throw new CustomException("账号已被冻结，请联系管理员!");
        }
        return jwtUtils.generateToken(user.getId());
    }

    @Override
    public int userAutonym(UserAutonymBo bo) {
        HcxAppUser user = getBaseMapper().selectById(SecurityUtils.getUserId());
        // 状态改为待审核
        user.setStatus(Constants.ONE);
        user.setRealName(bo.getRealName());
        user.setIdcard(bo.getIdcard());
        user.setCityCode(bo.getCityCode());
        user.setCityName(bo.getCityName());
        user.setAddress(bo.getAddress());
        return getBaseMapper().updateById(user);
    }

    @Override
    public UserAutonymVo getAutonym() {
        HcxAppUser user = getBaseMapper().selectById(SecurityUtils.getUserId());
        UserAutonymVo vo = new UserAutonymVo();
        vo.setRealName(user.getRealName());
        vo.setIdcard(user.getIdcard());
        vo.setAddress(user.getAddress());
        vo.setCityCode(user.getCityCode());
        vo.setCityName(user.getCityName());
        vo.setStatus(user.getStatus());
        return vo;
    }

    /**
     * @description: 参考书授权流程
     * https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
     * <p>
     * 目前用的uniapp封装的 uni.login  前端可以直接获取到openId
     * @author: kubilewang
     * @date: 2022/8/24
     * @param: [bo]
     * @Return: [bo]
     **/
    @Override
    public AjaxResult<AppThirdLoginVo> thirdLogin(ThirdLoginBo bo) {
        HcxAppUser hcxAppUser;
        if (bo.getLoginType().equals(AppUserLoginTypeEnum.WX_UID.getValue())) {
            hcxAppUser = getBaseMapper().selectOne(new LambdaQueryWrapper<HcxAppUser>().eq(HcxAppUser::getOpenId, bo.getOpenId()));
        } else {
            hcxAppUser = getBaseMapper().selectOne(new LambdaQueryWrapper<HcxAppUser>().eq(HcxAppUser::getAppleId, bo.getAppleId()));
        }

        // 如果是空 则为新用户  走注册流程
        if (ObjectUtil.isNotEmpty(hcxAppUser)) {
            if (Constants.FOUR.equals(hcxAppUser.getStatus())) {
                throw new CustomException("账号已被冻结，请联系管理员");
            }
            AppThirdLoginVo appThirdLoginVo = new AppThirdLoginVo();
            appThirdLoginVo.setUserId(hcxAppUser.getId());
            appThirdLoginVo.setPhonenumber(hcxAppUser.getPhonenumber());
            appThirdLoginVo.setOpenId(hcxAppUser.getOpenId());
            appThirdLoginVo.setStatus(hcxAppUser.getStatus());
            appThirdLoginVo.setNickName(bo.getNickName());
            appThirdLoginVo.setGender(bo.getGender());
            appThirdLoginVo.setCity(bo.getCity());
            appThirdLoginVo.setProvince(bo.getProvince());
            appThirdLoginVo.setCountry(bo.getCountry());
            appThirdLoginVo.setAvatarUrl(bo.getAvatarUrl());

            // 生成令牌
            String token = jwtUtils.generateToken(appThirdLoginVo.getUserId());
            appThirdLoginVo.setToken(token);


            return AjaxResult.success(appThirdLoginVo);
        }
        // 返回信息 在绑定手机号的时候统一注册
        AppThirdLoginVo appThirdLoginVo = new AppThirdLoginVo();
        if (bo.getLoginType().equals(AppUserLoginTypeEnum.WX_UID.getValue())) {
            appThirdLoginVo.setOpenId(bo.getOpenId());
        } else {
            appThirdLoginVo.setAppleId(bo.getAppleId());
        }
        appThirdLoginVo.setGender(bo.getGender());
        appThirdLoginVo.setAvatarUrl(bo.getAvatarUrl());

        return AjaxResult.success(appThirdLoginVo);

    }

    @Override
    public String savePhoneNumber(UserSavePhone bo) {
        //验证两次密码是否一致
        if (!bo.getPassword().equals(bo.getPasswordAgin())) {
            throw new CustomException("两次密码不一致,请重新输入。");
        }
        //校验验证码是否正确
        boolean result = this.authCode(bo.getPhonenumber(), bo.getAuthCode());
        if (!result) {
            throw new CustomException("验证码错误!");
        }

        Long tokenKey;

        // 判断此手机号已存在 则更新openId
        List<HcxAppUser> listUsers = hcxAppUserMapper.selectList(new LambdaQueryWrapper<HcxAppUser>().eq(HcxAppUser::getPhonenumber, bo.getPhonenumber()));
        if (CollectionUtil.isNotEmpty(listUsers)) {
            HcxAppUser yicunzai = listUsers.get(0);
            if (bo.getLoginType().equals(AppUserLoginTypeEnum.WX_UID.getValue())) {
                yicunzai.setOpenId(bo.getOpenId());
            } else {
                yicunzai.setAppleId(bo.getAppleId());
            }
            // 更新性别
            if (ObjectUtil.isNotEmpty(yicunzai.getSex())) {
                yicunzai.setSex(bo.getGender());
            }
            // 更新头像
            if (ObjectUtil.isNotEmpty(yicunzai.getAvatar())) {
                yicunzai.setAvatar(bo.getAvatarUrl());
            }
            getBaseMapper().updateById(yicunzai);
            tokenKey = yicunzai.getId();
        } else {

            // 注册号码
            HcxAppUser hcxAppUser = new HcxAppUser();
            hcxAppUser.setPhonenumber(bo.getPhonenumber());
            hcxAppUser.setPassword(SecurityUtils.encryptPassword(bo.getPassword()));
            hcxAppUser.setUserName(bo.getPhonenumber());


            if (bo.getLoginType().equals(AppUserLoginTypeEnum.WX_UID.getValue())) {
                hcxAppUser.setOpenId(bo.getOpenId());
            } else {
                hcxAppUser.setAppleId(bo.getAppleId());
            }

            hcxAppUser.setSex(bo.getGender());
            hcxAppUser.setAvatar(bo.getAvatarUrl());
            // 生成自己的邀请码
            while (true) {
                String yqcode = RandomUtil.randomNumbers(6);
                List<HcxAppUser> list = getBaseMapper().selectList(new LambdaQueryWrapper<HcxAppUser>().eq(HcxAppUser::getInviteCode, yqcode));
                if (CollectionUtil.isEmpty(list)) {
                    hcxAppUser.setInviteCode(yqcode);
                    break;
                }
            }
            hcxAppUser.setInviteFullCode(Constants.ZERO);
            hcxAppUser.setVipFlag(Constants.ZERO);
            hcxAppUser.setMerchantFlag(Constants.ZERO);
            hcxAppUser.setBalancePrice(new BigDecimal(Constants.ZERO));
            hcxAppUser.setFramPrice(new BigDecimal(Constants.ZERO));
            hcxAppUser.setSharePrice(new BigDecimal(Constants.ZERO));
            hcxAppUser.setMerchantPrice(new BigDecimal(Constants.ZERO));
            hcxAppUser.setNickName(NameUtils.getName());
            hcxAppUser.setSex(bo.getGender());
            hcxAppUser.setAvatar(bo.getAvatarUrl());
            hcxAppUser.setTwoNum(Long.valueOf(0));
            getBaseMapper().insert(hcxAppUser);

            tokenKey = hcxAppUser.getId();

        }

        // 生成令牌
        String token = jwtUtils.generateToken(tokenKey);

        return token;
    }

    @Override
    public AppUserVo getPersonalDate() {
        Long id = SecurityUtils.getUserId();
        return getVoById(id, AppUserVo.class);
    }

    @Override
    public int amendPassword(UserPwdBo bo) {
        Long id = SecurityUtils.getUserId();
        HcxAppUser sysUser = getBaseMapper().selectById(id);
        // 判断旧密码是否正确
        AssertUtils.isTrue(SecurityUtils.matchesPassword(bo.getPassword(), sysUser.getPassword()), "旧密码错误");
        // 判断新旧密码是否一致
        AssertUtils.isTrue(!SecurityUtils.matchesPassword(bo.getPasswordOne(), sysUser.getPassword()), "新旧密码不能相同");
        sysUser.setPassword(SecurityUtils.encryptPassword(bo.getPasswordOne()));
        return getBaseMapper().updateById(sysUser);
    }

    @Override
    public boolean pwdVerify(String oldPassword) {
        Long userId = SecurityUtils.getUserId();
        HcxAppUser user = getBaseMapper().selectById(userId);
        return user.getPassword().equals(oldPassword);
    }

    @Override
    public boolean payCodeVerify(String oldPayCode) {
        Long userId = SecurityUtils.getUserId();
        HcxAppUser user = getBaseMapper().selectById(userId);
        return SecurityUtils.matchesPassword(oldPayCode, user.getPassword());
    }

    @Override
    public int amendPayCode(PayPwdBo bo) {
        Long id = SecurityUtils.getUserId();
        HcxAppUser sysUser = getBaseMapper().selectById(id);
        // 判断旧密码是否正确
        AssertUtils.isTrue(SecurityUtils.matchesPassword(bo.getPassword(), sysUser.getPayPassword()), "旧密码错误");
        // 判断新旧密码是否一致
        AssertUtils.isTrue(!SecurityUtils.matchesPassword(bo.getPasswordOne(), sysUser.getPayPassword()), "新旧密码不能相同");
        sysUser.setPayPassword(SecurityUtils.encryptPassword(bo.getPasswordOne()));
        return getBaseMapper().updateById(sysUser);
    }

    @Override
    public int phoneCode(PayPwdBo bo) {
        Long id = SecurityUtils.getUserId();
        HcxAppUser sysUser = getBaseMapper().selectById(id);
        // 判断新旧密码是否一致
        AssertUtils.isTrue(!SecurityUtils.matchesPassword(bo.getPasswordOne(), sysUser.getPayPassword()), "新旧密码不能相同");
        sysUser.setPayPassword(SecurityUtils.encryptPassword(bo.getPasswordOne()));
        return getBaseMapper().updateById(sysUser);
    }

    @Override
    public List<HcxUserCoupon> getMyDiscountCoupon() {
        Long userId = SecurityUtils.getUserId();
        return userCouponMapper.selectList(new LambdaQueryWrapper<HcxUserCoupon>().eq(HcxUserCoupon::getUserId, userId).eq(HcxUserCoupon::getDelFlag, Constants.ZERO));
    }

    @Override
    @Transactional
    public int feedback(HcxUserOpinionsBo bo) {
        Long userId = SecurityUtils.getUserId();
        HcxAppUser user = getBaseMapper().selectById(userId);
        HcxUserOpinions userOpinions = new HcxUserOpinions();
        userOpinions.setUserId(userId);
        userOpinions.setUserName(user.getUserName());
        userOpinions.setRealName(user.getRealName());
        userOpinions.setDelFlag(Constants.ZERO);
        userOpinions.setPhonenumber(user.getPhonenumber());
        userOpinions.setCreateTime(new Date());
        userOpinions.setDescription(bo.getDescription());
        userOpinions.setContactInfo(bo.getContactInfo());
        userOpinionsMapper.insert(userOpinions);
        HcxUserOpinionsPics opinionsPics = new HcxUserOpinionsPics();
        opinionsPics.setUserName(user.getUserName());
        opinionsPics.setOpinionId(userOpinions.getId());
        opinionsPics.setPicUrl(bo.getPicUrl());
        opinionsPics.setDelFlag(Constants.ZERO);
        opinionsPics.setRealName(user.getRealName());
        opinionsPics.setUserId(userId);
        opinionsPics.setCreateTime(new Date());
        return opinionsPicsMapper.insert(opinionsPics);
    }

    @Override
    public int changePhonenumber(String phonenumber, String authCode) {
        HcxAppUser user = new HcxAppUser();
        Long userId = SecurityUtils.getUserId();
        user.setId(userId);
        AssertUtils.isTrue(authCode(phonenumber, authCode), "修改失败，验证码失败");
        user.setPhonenumber(phonenumber);
        return getBaseMapper().updateById(user);

    }

    @Override
    public boolean quit() {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        Long userId = SecurityUtils.getUserId();
        boolean result = redisCache.deleteObject(Constants.LOGIN_TOKEN_KEY + loginUser.getToken());
        result = redisCache.deleteObject(Constants.LOGIN_USERID_KEY + userId);
        return result;
    }

    @Override
    public int update(AppUserUpdateBo bo) {
        Long userId = SecurityUtils.getUserId();
        HcxAppUser user = getBaseMapper().selectById(userId);
        user.setCityCode(bo.getCityCode());
        user.setCityName(bo.getCityName());
        user.setNickName(bo.getNickName());
        user.setSex(bo.getSex());
        user.setAvatar(bo.getAvatar());
        user.setRealName(bo.getRealName());
        user.setPayPassword(bo.getPayPassword());
        user.setProvinceCode(bo.getProvinceCode());
        user.setProvinceName(bo.getProvinceName());
        user.setDistrictsCode(bo.getDistrictsCode());
        user.setDistrictsName(bo.getDistrictsName());
        user.setCarNum(bo.getCarNum());
        user.setAddress(bo.getAddress());
        user.setOpenId(bo.getOpenId());
        return getBaseMapper().updateById(user);
    }

    @Override
    public int resetpwd(AppResetpwd bo) {
        if (!bo.getOnePwd().equals(bo.getTwoPwd())) {
            throw new CustomException("两次输入的密码不一致!");
        }
        String msgCode = stringRedisTemplate.opsForValue().get(bo.getPhoneNumber());
        if (StrUtil.isEmpty(msgCode) || !msgCode.equals(bo.getCode())) {
            throw new CustomException("短信验证码错误!");
        }
        HcxAppUser hcxAppUser = hcxAppUserMapper.selectOne(new LambdaQueryWrapper<HcxAppUser>().eq(HcxAppUser::getPhonenumber, bo.getPhoneNumber()));
        hcxAppUser.setPassword(SecurityUtils.encryptPassword(bo.getOnePwd()));
        int i = hcxAppUserMapper.updateById(hcxAppUser);
        return i;
    }
}
